unit QSocketServer;

interface

uses
  Classes, SysUtils,
  IdBaseComponent, IdComponent, IdTCPServer, IdThreadMgrDefault,
  QPeerThread,  siAuto, Graphics;

Type
  TOnClientRequest = Procedure(Sender:TObject; cmd:integer; Data:String) of Object;
  TQSocketServer = Class(TComponent)
    private
      FThreadList: TThreadList;
      FPort: integer;
      FTCP : TIdTCPServer;
      FQSocketProcess: TComponent;
      FActive: Boolean;
      FOnClientRequest: TOnClientRequest;

      procedure SetPort(const Value: integer);
      procedure SetActive(const Value: Boolean);

      Procedure EventClinetConnect(AThread: TIdPeerThread);
      procedure EventClientDisconnect(AThread: TIdPeerThread);
      procedure SetProcess(const Value: TComponent);
    protected
    public
      Constructor Create(AOwner:TComponent); override;
      Destructor  Destroy; override;

      Procedure BroadCast(Data:Pointer; Size:integer);

      property  Active: Boolean read FActive Write SetActive;
      Property  Process:TComponent read FQSocketProcess Write SetProcess;
    published
      property Port: integer read FPort Write SetPort;
      property OnClientRequest:TOnClientRequest read FOnClientRequest Write FOnClientRequest;
  End;

Type
  TCustomQSocketProcess = Class(TComponent)
  private
      FTCP: TIdTCPServer;
      procedure SetFTCP(const Value: TIdTCPServer);
    protected
      FOwner: TComponent;
      procedure Do_FireEvent(Cmd:integer; Data:String);
      Procedure TCPExecute(AThread: TIdPeerThread); dynamic;
    public
      Constructor Create(AOwner:TComponent); override;
      property TCP: TIdTCPServer read FTCP Write SetFTCP;
  End;  

implementation


{ TQSocketServer }

procedure TQSocketServer.BroadCast(Data: Pointer; Size: integer);
var
  list:TList;
  I: Integer;
  Thread: TQPeerThread;
begin
  list := FThreadList.LockList;
  try
    for I := 0 to List.Count - 1 do
    begin
      Try
        Thread := TQPeerThread( list.Items[i] );
        Thread.Add( Data, Size );
      Except
      End;
    end;
  finally
    FThreadList.UnlockList;
  end;
end;

constructor TQSocketServer.Create(AOwner: TComponent);
begin
  inherited;

  FThreadList := TThreadList.Create;

  FTCP := TIdTCPServer.Create(self);
  FTCP.ThreadClass := TQPeerThread;
  FTCP.ThreadMgr :=    TIdThreadMgrDefault.Create(Self);
  FTCP.TerminateWaitTime := 5000;
  FTCP.OnConnect     := EventClinetConnect;
  FTCP.OnDisconnect  := EventClientDisconnect;

//  FQSocketProcess := TQSocketProcess.Create;
//  FQSocketProcess.TCP := FTCP;

  FActive := False;
end;

procedure TQSocketServer.SetProcess(const Value: TComponent);
begin
  FQSocketProcess := Value;
  TCustomQSocketProcess(FQSocketProcess).TCP := FTCP;
end;

destructor TQSocketServer.Destroy;
begin
  if FTCP.Active then FTCP.Active := False;
  
  FThreadList.Free;
  FreeAndNil( FTCP );
  inherited;
end;

procedure TQSocketServer.EventClientDisconnect(AThread: TIdPeerThread);
var
  list: TList;
  index:integer;
begin

  list := FThreadList.LockList;
  try
    index := list.IndexOf( AThread );
    if index >= 0 then
    begin
      list.Delete( index );
//      siMain.LogColored(clGreen, '%s DISCONNECT. ', [ Athread.Connection.Socket.Binding.PeerIP]);
    end;
  finally
    FThreadList.UnlockList;
  end;
end;

procedure TQSocketServer.EventClinetConnect(AThread: TIdPeerThread);
var
  list:TList;
begin
  list := FThreadList.LockList;
  try
    list.Add( AThread );
//    siMain.LogColored(clGreen, '%s CONNECT. ', [ Athread.Connection.Socket.Binding.PeerIP]);
  finally
    FThreadList.UnlockList;
  end;
end;

procedure TQSocketServer.SetActive(const Value: Boolean);
begin
  if value = FActive then Exit;

  if not Assigned(FQSocketProcess) then
    Raise Exception.Create( 'TQSocketProcess was not assigned.' );

  try
    FTCP.Active := Value;
  Except
    Exit;
  end;

  FActive := Value;
end;

procedure TQSocketServer.SetPort(const Value: integer);
begin
  if FTCP.Active then
    Raise Exception.Create( 'Can''t change port while server running..' );
    
  FPort := Value;
  FTCP.DefaultPort := FPort;
end;


{ TCustomQSocketProcess }

constructor TCustomQSocketProcess.Create(AOwner: TComponent);
begin
  inherited;
  FOwner := AOwner;
end;

procedure TCustomQSocketProcess.Do_FireEvent(Cmd: integer; Data:String);
begin
  if Assigned( TQSocketServer(FOwner).FOnClientRequest ) then
    TQSocketServer(FOwner).FOnClientRequest( FOwner, cmd, Data );
end;

procedure TCustomQSocketProcess.SetFTCP(const Value: TIdTCPServer);
begin
  FTCP := Value;
  FTCp.OnExecute := TCPExecute;
end;

procedure TCustomQSocketProcess.TCPExecute(AThread: TIdPeerThread);
begin

end;

end.
